#include <stdio.h>
#include <stdlib.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <string.h>

#define DEPTH 2

// ERROR HANDLER, GENERIC
static int ErrorHandler (Display *display, XErrorEvent *error)
{
   //printf ("\n error! \n");
   return 0;
}
// END ERROR HANDLER

// GET THE ACTUAL TEXT!!! - This is where it all comes unstuck
void GetWindowProperties (Display *display, Window window)
{
   Atom *atoms;
   int i, j;
   Atom type;
   int format, result, status;
   unsigned long len, bytesLeft;
   unsigned char *data;
   char *atomName;
   XTextProperty textData;
  
   atoms = XListProperties (display, window, &i);
   if (i)
   {
      for (j=0; j < i; j++)
      {
         atomName = XGetAtomName(display, atoms[i]);
       if (atomName)
            printf ("Atom name: %s\n", atomName);
         
       status = XGetTextProperty (display, window, &textData, atoms[i]);
       if (status)
       {
             printf ("Atom text: %s\n", textData.value);
       }
      }
   }
}
// END GET THE ACTUAL TEXT!!! - This is where it all comes unstuck

// ENUMARATE THROUGH WINDOWS AND DISPLAY THEIR TITLES
void EnumerateWindows (Display *display, Window rootWindow, int showErrors, int showStatus)
{
   static int level = 0;
   Window parent;
   Window *children;
   Window *child;
   unsigned int noOfChildren;
   int status;
   int i;
   XWindowAttributes wattrs;;
   XTextProperty wmName;
   char **list;
  
   status = XGetWMName (display, rootWindow, &wmName);
   if ((status) && (wmName.value) && (wmName.nitems))
   {
      status = XmbTextPropertyToTextList (display, &wmName, &list, &i);
      if ((status >= Success) && (i) && (*list)) {
         printf ("INFO - Found window with name '%s' \n", (char*) strdup (*list));
         status = XGetWindowAttributes(display, rootWindow, &wattrs);
         if(status >= Success) {
           printf("x:%d, y:%d, w:%d, h:%d, bw:%d\n", wattrs.x, wattrs.y, 
                  wattrs.width, wattrs.height, wattrs.border_width);
         }
      }
   }
#ifdef GET_PROPS  
   GetWindowProperties (display, rootWindow);
#endif //GET_PROPS  
   level++;
   if(level >= DEPTH) return;
   status = XQueryTree (display, rootWindow, &rootWindow, &parent, &children, &noOfChildren);
  
   if (status == 0)
   {
      if (showErrors)
         printf ("ERROR - Could not query the window tree. Aborting.\n");
      return;
   }
  
   if (noOfChildren == 0)
   {
      if (showErrors)
         printf ("ERROR - No children found. Aborting.\n");
      return;
   }
   else
   {
      if (showStatus)
         printf ("STATUS - %i number of child windows found.\n", noOfChildren);
   }
  
   for (i=0; i < noOfChildren; i++)
   {
      EnumerateWindows (display, children[i], showErrors, showStatus);
   }
  
   XFree ((char*) children);
}
// END ENUMERATE WINDOWS

int main(int argc, char *argv[])
{
   // CONNECT TO THE XSERVER
   Display *display;
   int depth;
   int screen;
   int connection;
  
   display = XOpenDisplay (getenv("DISPLAY"));
   screen = DefaultScreen (display);
   depth = DefaultDepth (display, screen);
   connection = ConnectionNumber (display);
   XSetErrorHandler (ErrorHandler);
  
   printf ("XWinSpy - by van\n");
   printf ("----------------\n");
   printf ("Display: %s\n", XDisplayName((char*)display));
   printf ("Width: %d\n", DisplayWidth(display, screen));
   printf ("Height: %d\n", DisplayHeight(display, screen));
   printf ("Connection: %d\n", connection);
   printf ("Color Depth: %d\n", depth);
   // END CONNECT TO THE XSERVER
  
   // RETRIEVE ROOT WINDOW
   Window rootWindow;
  
   rootWindow = RootWindow (display, screen); 
   // END RETRIEVE ROOT WINDOW
  
   // LOOP THROUGH ALL WINDOWS
   EnumerateWindows (display, rootWindow, 0, 0);
   // END LOOP THROUGH ALL WINDOWS
  
   // DISCONNECT FROM THE XSERVER
   XCloseDisplay (display);
   // END DISCONNECT FROM THE XSERVER

  return EXIT_SUCCESS;
} 
